<!doctype html>

<title>09 Component Classes - React From Zero</title>

<script src="https://unpkg.com/react@16.4.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.4.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/prop-types@15.6.1/prop-types.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<script src="https://unpkg.com/create-react-class@15.6.3/create-react-class.js">
// React.createClass was removed from React 16, it's now a own package
</script>

<div id="app"></div>

<script type="text/babel">
// Often a component needs to maintain some internal state
// for example if there is an interaction involved
// in this case a component function is not sufficient
// the component function can only have properties and no state
// we need a component class with a render function
var MyComponent = createReactClass({
  // used for type-checking of the properties
  // same as with the component function
  propTypes: {
    color: PropTypes.string
  },

  // this method sets default values for missing properties
  // it will be called by React
  // before the components gets mounted into the DOM
  getDefaultProps: function() {
    return { color: "green" };
  },

  // this method sets the initial state for the component
  // it will be called by React
  // before the components gets mounted into the DOM
  // if this method is missing, this.state will be undefined
  getInitialState: function() {
    // The state can be any JavaScript value, often it is an object
    return { times: 0 };
  },

  // this method handles all the clicks on the <span> element
  handleClick: function() {
    // setState() can be called with an object that contains the new
    // state. Normally this triggers a call of render(), but React can
    // batch multiple calls and defer the render() call (make the call
    // asynchronous). To prevent this, setState can take a callback
    // instead.

    // This can lead to unexpected behavior, if we rely on this.state
    // or this.props for our calculations
    // this.setState({times: this.state.times + 1})

    // The callback version doesn't have this problem, it gets the
    // right state and props at time of the update
    this.setState(function(prevState, props) {
      return { times: prevState.times + 1 };
    });
  },

  // this method will be called by React
  // after the component got mounted into the DOM
  // also every time this.setState() was called
  // it's like the component function from before
  // but without a props argument
  render: function() {
    // using the prop given by the creator of this component
    // properties are now in this.props instead of the props argument
    var style = { color: this.props.color };

    // returning an element with a click-handler and the props and
    // state values. state is stored in this.state
    return (
      <span onClick={this.handleClick} style={style}>
        Clicked {this.state.times} times
      </span>
    );
  }
});

// creating some instances of the interactive stateful component class
// one with default color
// Everything works exactly like with the simpler component functions
// The interface has not changed for the user of this component
var reactElement = (
  <div>
    <MyComponent color="red" />
    <br />
    <MyComponent color="blue" />
    <br />
    <MyComponent />
  </div>
);

var renderTarget = document.getElementById("app");

ReactDOM.render(reactElement, renderTarget);  
</script>